package com.tiancheng.trade.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.order.bo.RefundNotifyBO;
import com.tiancheng.trade.order.bo.RefundOrdersDetailSubmitBO;
import com.tiancheng.trade.order.bo.SubOrderRefundBO;
import com.tiancheng.trade.order.enums.RefundStatusEnum;
import com.tiancheng.trade.order.mapper.IntRefundMapper;
import com.tiancheng.trade.order.model.IntRefund;
import com.tiancheng.trade.order.service.IntOrderService;
import com.tiancheng.trade.order.service.IntRefundService;
import com.tiancheng.trade.order.vo.api.RefundAuditVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 退款service
 */
@Service
@Slf4j
public class IntRefundServiceImpl implements IntRefundService {
    @Autowired
    private IntRefundMapper intRefundMapper;
    @Resource
    private IntOrderService intOrderService;


    @Override
    @Transactional
    public List<IntRefund> saveRefundResult(RefundNotifyBO refundNotifyBO) throws BusinessException {

        boolean success = "success".equalsIgnoreCase(refundNotifyBO.getStatus());

        QueryWrapper<IntRefund> conditions = new QueryWrapper<>();
        conditions.eq("payment_id", refundNotifyBO.getPaymentId());

        List<IntRefund> refunds = intRefundMapper.selectList(conditions);
        BusinessErrorInfoEnum.ORDER_REFUND_NO_DATA.assertIsTrue(refunds.size() > 0);

        if(refunds.get(0).getRefundStatus().equals(RefundStatusEnum.success.getCode())){
            BusinessErrorInfoEnum.ORDER_REFUND_REPEAT_NOTICE.assertFail();
        }
        int refundAmount = refunds.stream().mapToInt(IntRefund::getRefundAmount).sum();
        // 实退金额可能会有差异
        //BusinessErrorInfoEnum.ORDER_REFUND_AMOUNT_DIFF.assertIsTrue(refundAmount == refundNotifyBO.getAmount());
        // 如果实际退款金额不一样，则需要重新修正退款金额
        if(refundAmount!=refundNotifyBO.getAmount()){
            log.info("退款回调，实退金额与申请金额不一致，申请：{}，实退：{}",refundAmount,refundNotifyBO.getAmount());
            RefundAuditVO refundAuditVO = new RefundAuditVO();
            refundAuditVO.setOrderId(refunds.get(0).getOrderId());
            refundAuditVO.setPaymentId(refundNotifyBO.getPaymentId());
            this.extracted(refundAuditVO,refunds,refundNotifyBO.getFlowId(),refundNotifyBO.getAmount());
        }
        IntRefund updateRefund = new IntRefund();
        updateRefund.setFlowId(refundNotifyBO.getFlowId());
        updateRefund.setRefundTime(refundNotifyBO.getRefundTime());
        updateRefund.setRefundStatus(success ? RefundStatusEnum.success.getCode() : RefundStatusEnum.fail.getCode());
        intRefundMapper.update(updateRefund, conditions);

        // 修改订单状态
        String orderId = refunds.get(0).getOrderId();
        List<SubOrderRefundBO> subOrderRefundBOS = new ArrayList<>();
        for (IntRefund intRefund : refunds) {
            String refundStatus = success ? RefundStatusEnum.success.getCode() : RefundStatusEnum.fail.getCode();
            Integer subOrderRefundAmount = success ? intRefund.getRefundAmount() : 0;
            subOrderRefundBOS.add(new SubOrderRefundBO(orderId, intRefund.getSubOrderId(), subOrderRefundAmount, refundStatus));
        }
        intOrderService.refund(success, orderId, subOrderRefundBOS);

        refunds.forEach(refund -> {
            refund.setRefundTime(updateRefund.getRefundTime());
            refund.setRefundStatus(updateRefund.getRefundStatus());
            refund.setFlowId(refundNotifyBO.getFlowId());
        });
        return refunds;
    }

    /**
     * 修改实际退款金额
     * @param refundAuditVO
     * @param refunds 对款流水
     * @param flowId 退款流水号
     * @param amount 总的实退金额
     */
    private void extracted(RefundAuditVO refundAuditVO, List<IntRefund> refunds, String flowId, int amount) {
        // 实际退款金额
        int totalAmount= refunds.stream().mapToInt(IntRefund::getRefundApplyAmount).sum();
        List<RefundOrdersDetailSubmitBO> refundOrdersDetailSubmitBOS = new ArrayList<>(refunds.size());
        // 累计实退金额
        int refundedAmount=0;
        for (int i = 0; i < refunds.size(); i++) {
            IntRefund intRefund = refunds.get(i);
            int refundInvoiceAmount=0;
            if (i == refunds.size() - 1) {
                refundInvoiceAmount=(amount - refundedAmount);
            } else {
                // 1、计算子订单所占总金额的比例，小数点后取10位，然后截取
                // 2、总优惠金额*子订单比例，然后四舍五入取整
                int divide = BigDecimal.valueOf(intRefund.getRefundApplyAmount()).
                        divide(BigDecimal.valueOf(totalAmount), 10,BigDecimal.ROUND_DOWN)
                        .multiply(BigDecimal.valueOf(amount)).setScale(0, BigDecimal.ROUND_UP).intValue();
                // 如果平摊后的实退金额大于支付金额，则设置实退金额=支付金额
                if(divide>intRefund.getSubOrderPayAmount()){
                    divide=intRefund.getSubOrderPayAmount();
                }
                refundInvoiceAmount=divide;
                refundedAmount+=divide;
            }
            refundOrdersDetailSubmitBOS.add(new RefundOrdersDetailSubmitBO(refundAuditVO.getOrderId(), refundAuditVO.getPaymentId(),
                    intRefund.getSubOrderId(), flowId, refundInvoiceAmount, intRefund.getRefundApplyAmount(), LocalDateTime.now()));
            log.info("修改子订单实退金额，申请：{}，申请实退：{}，最后实退：{}",intRefund.getRefundAmount(),intRefund.getRefundApplyAmount(),refundInvoiceAmount);
            // 设置实退金额
            refunds.get(i).setRefundAmount(refundInvoiceAmount);
        }
        intRefundMapper.updateBatch(refundOrdersDetailSubmitBOS);
    }

}
